/*
 * Cube.cpp
 *
 *  Created on: 31.1.2013
 *      Author: Travis
 */

#ifdef _WIN32 
#include <windows.h> 
#endif

#include "Cube.h"
#include "../scene/World.h"

namespace DataTypes
{

Cube::Cube(std::vector<glm::vec3> _vertexes)
{
	vertexes = _vertexes;
	size = (vertexes[4].y - vertexes[0].y) / 2.0;
	center = glm::vec3(0.0);

	shaderID = Shader::sPool->getProgramID("cube");

	size_x = 0.0;
	size_y = 0.0;
}

Cube::Cube(float _size)
{
	size = _size;
	size_x = 0.0;
	size_y = 0.0;
	center = glm::vec3(0.0);

	// bottom
	vertexes.push_back(glm::vec3(0.0f, -(size / 2), size)); // A
	vertexes.push_back(glm::vec3(0.0f, -(size / 2), 0.0f)); // B
	vertexes.push_back(glm::vec3(size, -(size / 2), 0.0f)); // C
	vertexes.push_back(glm::vec3(size, -(size / 2), size)); // D

	//top
	vertexes.push_back(glm::vec3(0.0f, size / 2, size)); // A
	vertexes.push_back(glm::vec3(0.0f, size / 2, 0.0f)); // B
	vertexes.push_back(glm::vec3(size, size / 2, 0.0f)); // C
	vertexes.push_back(glm::vec3(size, size / 2, size)); // D

	shaderID = Shader::sPool->getProgramID("cube");
}

Cube::Cube(glm::vec3 _center, float _size)
{
	size = _size;
	size_x = 0.0;
	size_y = 0.0;
	center = _center;

	float s = size / 2;

	// bottom
	vertexes.push_back(glm::vec3(center.x - s, center.y - s, center.z + s)); // A
	vertexes.push_back(glm::vec3(center.x - s, center.y - s, center.z - s)); // B
	vertexes.push_back(glm::vec3(center.x + s, center.y - s, center.z - s)); // C
	vertexes.push_back(glm::vec3(center.x + s, center.y - s, center.z + s)); // D

	//top
	vertexes.push_back(glm::vec3(center.x - s, center.y + s, center.z + s)); // A
	vertexes.push_back(glm::vec3(center.x - s, center.y + s, center.z - s)); // B
	vertexes.push_back(glm::vec3(center.x + s, center.y + s, center.z - s)); // C
	vertexes.push_back(glm::vec3(center.x + s, center.y + s, center.z + s)); // D

	shaderID = Shader::sPool->getProgramID("cube");
}

Cube::Cube(glm::vec3 _center, float _size_x, float _size_y)
{
	size = 0.0;
	size_x = _size_x;
	size_y = _size_y;
	center = _center;

	float s = _size_x / 2.0;
	float sy = _size_y / 2.0;

	// bottom
	vertexes.push_back(glm::vec3(center.x - s, center.y - sy, center.z + s)); // A
	vertexes.push_back(glm::vec3(center.x - s, center.y - sy, center.z - s)); // B
	vertexes.push_back(glm::vec3(center.x + s, center.y - sy, center.z - s)); // C
	vertexes.push_back(glm::vec3(center.x + s, center.y - sy, center.z + s)); // D

	//top
	vertexes.push_back(glm::vec3(center.x - s, center.y + sy, center.z + s)); // A
	vertexes.push_back(glm::vec3(center.x - s, center.y + sy, center.z - s)); // B
	vertexes.push_back(glm::vec3(center.x + s, center.y + sy, center.z - s)); // C
	vertexes.push_back(glm::vec3(center.x + s, center.y + sy, center.z + s)); // D

	shaderID = Shader::sPool->getProgramID("cube");
}

Cube::~Cube()
{
	vertexes.clear();
}

float Cube::GetDiagonalOfBase()
{
	return sqrt(
			pow(abs(vertexes[0].z) + abs(vertexes[3].z), 2)
					+ pow(abs(vertexes[2].x) + abs(vertexes[3].x), 2));
}

void Cube::Scale(float add)
{
	glm::mat3 smatrix(add);

	for (unsigned int i = 0; i < vertexes.size(); i++)
		vertexes[i] = smatrix * vertexes[i];

}

void Cube::printCube()
{
	std::cout << "Cube info" << std::endl;

	for (unsigned int i = 0; i < vertexes.size(); i++)
		std::cout << i << " x: " << vertexes[i].x << " y: " << vertexes[i].y
				<< " z: " << vertexes[i].z << std::endl;
}

void Cube::drawCube()
{
	drawCube(glm::vec3(0.0), 0.0, glm::vec3(1.0));
}

void Cube::drawCube(glm::vec3 pos, float angle, glm::vec3 color)
{
	// get matrix
	glm::mat4 ModelMatrix = glm::mat4(1.0f);
	glm::mat4 ViewMatrix = glm::translate(World::world->getView(),
			glm::vec3(pos.x, pos.y, pos.z));
	ViewMatrix = glm::rotate(ViewMatrix, angle, glm::vec3(0.0f, 1.0f, 0.0f));
	glm::mat4 MVP = World::world->getProjection() * ViewMatrix * ModelMatrix;

	// start shader program

	glUseProgram(shaderID);

	// send matrix to shader
	glUniformMatrix4fv(glGetUniformLocation(shaderID, "MVP"), 1, GL_FALSE,
			&MVP[0][0]);
	glUniform3f(glGetUniformLocation(shaderID, "color"), color.x, color.y,
			color.z);

	glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);

	glBegin(GL_QUADS);
	glVertex3f(vertexes[0].x, vertexes[0].y, vertexes[0].z);
	glVertex3f(vertexes[1].x, vertexes[1].y, vertexes[1].z);
	glVertex3f(vertexes[2].x, vertexes[2].y, vertexes[2].z);
	glVertex3f(vertexes[3].x, vertexes[3].y, vertexes[3].z);

	glVertex3f(vertexes[4].x, vertexes[4].y, vertexes[4].z);
	glVertex3f(vertexes[5].x, vertexes[5].y, vertexes[5].z);
	glVertex3f(vertexes[6].x, vertexes[6].y, vertexes[6].z);
	glVertex3f(vertexes[7].x, vertexes[7].y, vertexes[7].z);

	glVertex3f(vertexes[5].x, vertexes[5].y, vertexes[5].z);
	glVertex3f(vertexes[6].x, vertexes[6].y, vertexes[6].z);
	glVertex3f(vertexes[2].x, vertexes[2].y, vertexes[2].z);
	glVertex3f(vertexes[1].x, vertexes[1].y, vertexes[1].z);

	glVertex3f(vertexes[4].x, vertexes[4].y, vertexes[4].z);
	glVertex3f(vertexes[7].x, vertexes[7].y, vertexes[7].z);
	glVertex3f(vertexes[3].x, vertexes[3].y, vertexes[3].z);
	glVertex3f(vertexes[0].x, vertexes[0].y, vertexes[0].z);
	glEnd();

	glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);

	glUseProgram(0);
}

bool Cube::cubeInCube(Cube cube)
{
	return ((vertexes[3].x >= cube.getVertexes()[0].x)
			&& (vertexes[0].x <= cube.getVertexes()[3].x))
			&& ((vertexes[4].y >= cube.getVertexes()[0].y)
					&& (vertexes[0].y <= cube.getVertexes()[4].y))
			&& ((vertexes[0].z >= cube.getVertexes()[1].z)
					&& (vertexes[1].z <= cube.getVertexes()[0].z));
}

bool Cube::cubeInCubeThisMoved(Cube cube, float angle, glm::vec3 pos)
{
	return (((vertexes[3].x + pos.x) >= cube.getVertexes()[0].x)
			&& ((vertexes[0].x + pos.x) <= cube.getVertexes()[3].x))
			&& (((vertexes[4].y + pos.y) >= cube.getVertexes()[0].y)
					&& ((vertexes[0].y + pos.y) <= cube.getVertexes()[4].y))
			&& (((vertexes[0].z + pos.z) >= cube.getVertexes()[1].z)
					&& ((vertexes[1].z + pos.z) <= cube.getVertexes()[0].z));
}

bool Cube::pointInCube(glm::vec3 X)
{
	return pointInCube(0.0, glm::vec3(0.0), X);
}

bool Cube::pointInCube(float angle, glm::vec3 pos, glm::vec3 X)
{

	// check y value for collision
	if ((X.y > (vertexes[0].y + pos.y)) && (X.y < (vertexes[4].y + pos.y)))
	{
		Rectangle2D Bottom;

		Bottom.setA(glm::vec2(vertexes[0].x, vertexes[0].z));
		Bottom.setB(glm::vec2(vertexes[1].x, vertexes[1].z));
		Bottom.setC(glm::vec2(vertexes[2].x, vertexes[2].z));
		Bottom.setD(glm::vec2(vertexes[3].x, vertexes[3].z));

		//return Bottom.pointInRectangle2D(angle, glm::vec2(pos.x,pos.z), glm::vec2(X.x, X.z));
		return Bottom.pointInRectangle2D(glm::vec2(X.x, X.z),
				glm::vec2(pos.x, pos.z));
	}

	return 0;
}

const std::vector<glm::vec3>& Cube::getVertexes() const
{
	return vertexes;
}

void Cube::setVertexes(const std::vector<glm::vec3>& vertexes)
{
	this->vertexes = vertexes;
}

const glm::vec3& Cube::getCenter() const
{
	return center;
}

void Cube::setCenter(const glm::vec3& center)
{
	this->center = center;
}

float Cube::getSize() const
{
	return size;
}

void Cube::setSize(float size)
{
	this->size = size;
}
}
